package cn.org.wangchangjiu.redis.application.rank;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author wangchangjiu
 * @Classname StringRedisZsetRankingUtils
 * @Description 排行榜工具类
 * @Date 2023/12/5 20:04
 */
public class StringRedisZsetRanking {

    public static final long SCORE_OFFSET = Double.valueOf(Math.pow(10, 11)).longValue();

    public static final long MAX_TIME = 9999999999L;

    private StringRedisTemplate redisTemplate;

    public StringRedisZsetRanking(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


    public <T extends RankingDto> T get(String key, String currId, Integer end){

        RankingDto rankingDto = new RankingDto<>();

        Set<ZSetOperations.TypedTuple<String>> set = redisTemplate.opsForZSet().reverseRangeWithScores(key, 0, end);

        if(!CollectionUtils.isEmpty(set)){

             List<RankingDto.RankingItemDto> rankings = set.stream().sorted((o1, o2) -> (int) (o2.getScore() - o1.getScore())).map(
                    e -> {
                        //取出原星数
                        long score = e.getScore() == null ? 0 : e.getScore().longValue() / SCORE_OFFSET;
                        return new RankingDto.RankingItemDto(e.getValue(), 0, score, 0L);
                    }).collect(Collectors.toList());

            int ranking = 1;
            int lastUserIndex = 0;
            RankingDto.RankingItemDto curr = null;
            for(RankingDto.RankingItemDto item : rankings){
                ranking++;
                if(currId.equals(item.getId())){
                    // 当前
                    curr = item;
                    lastUserIndex = ranking - 2;
                }
                item.setRanking(ranking ++);
            }

            if(curr == null){
                Double score = redisTemplate.opsForZSet().score(key, currId);
                long currentStar = score == null ? 0 : score.longValue() / SCORE_OFFSET;
                curr = new RankingDto.RankingItemDto(currId, 0, currentStar, 0L);
                lastUserIndex = Math.min(rankings.size() - 1, end);
            }

            if((!CollectionUtils.isEmpty(rankings)) && lastUserIndex >= 0){
                RankingDto.RankingItemDto rankingItemDto = rankings.get(lastUserIndex);
                Long differenceVal = rankingItemDto.getVal() - curr.getVal();
                // 距离上一个还差多少
                curr.setLastDifferenceVal(differenceVal);
            }

            rankingDto.setRankingList(rankings);
            rankingDto.setCurrRanking(curr);
        }
        return (T) rankingDto;
    }

    public void add(String key, String value, long score) {
        Double oldScore = redisTemplate.opsForZSet().score(key, value);
        long currentStar = oldScore == null ? 0 : oldScore.longValue() / SCORE_OFFSET;
        long total = score + currentStar;
        //最终score：一共19位，后10位是时间戳的倒序，前8位是真正段位积分数
        long totalScore = (total * SCORE_OFFSET) + MAX_TIME - System.currentTimeMillis()/1000;
        redisTemplate.opsForZSet().add(key, value, totalScore);
    }


}
